package de.haw.gka.a1;


import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Iterator;

import org.jgrapht.DirectedGraph;
import org.jgrapht.UndirectedGraph;
import org.jgrapht.graph.AbstractGraph;
import org.jgrapht.graph.DefaultDirectedWeightedGraph;
import org.jgrapht.graph.DefaultEdge;
import org.jgrapht.graph.DefaultWeightedEdge;
import org.jgrapht.graph.WeightedPseudograph;

public class SaveGraph {
	
	public SaveGraph(){		
	}

	private void out(String str){
		System.out.println(str);
	}

	private boolean isDefaultEgde = false;
	private boolean isString = false;
	
	public boolean save(String name,  AbstractGraph<?, ?> graph){		
		// File anlegen
	     File file = new File(name+".gka");
	     if(file.exists()) {
	    	 out("----------------------------");
	    	 out("Dateiname schon vorhanden, bitte einen neuen wählen");
	    	 out("Speicherung fehlgeschlagen!");
	    	 out("----------------------------");
	    	 return false;
	     }	 	     
	     Iterator<?> iterEdge = graph.edgeSet().iterator();
			while(iterEdge.hasNext()){
				Object obj = iterEdge.next();
				if(obj instanceof DefaultEdge) {
					isDefaultEgde = true;
					break;
				}else break;
			}
			Iterator<?> isVertex = graph.vertexSet().iterator();
			while(isVertex.hasNext()){
				Object obj = isVertex.next();
				if(obj instanceof String) {
					isString = true;
					break;
				}else
					break;			
			}
			try {
				FileWriter writer = new FileWriter(file);
				boolean tmp = false;
				if (isDefaultEgde && isString) {
					out("String && DefaultEdge ");
					AbstractGraph<String, DefaultEdge> tgraph = (AbstractGraph<String, DefaultEdge>) graph;
					tmp = saveGraphStringDefaultEdge(tgraph, writer);
				} else if (isString && !isDefaultEgde) {
					out("String & DefaultWeightedEdge ");
					AbstractGraph<String, DefaultWeightedEdge> tgraph = (AbstractGraph<String, DefaultWeightedEdge>) graph;
					tmp = saveGraphStringDefaultWeightedEdge(tgraph, writer);
				} else {
					out("Knoten & DefaultWeightedEdge ");
					AbstractGraph<Knoten, DefaultWeightedEdge> tgraph = (AbstractGraph<Knoten, DefaultWeightedEdge>) graph;
					tmp = saveGraphKnotenDefaultWeightedEdge(tgraph, writer);
				}
				return tmp;
			 } catch (IOException e) {
					return false;
			}  
	}
	
	private boolean saveGraphKnotenDefaultWeightedEdge(AbstractGraph<Knoten, DefaultWeightedEdge> aGraph, FileWriter aWriter) throws IOException{
		boolean tmp = false;
		if(aGraph instanceof WeightedPseudograph){
			aWriter.write("#ungerichtet");
			aWriter.write(System.getProperty("line.separator"));
			aWriter.write("#gewichtet#attributiert");
			tmp = saveGewichtetUnGerichtetGraph(aGraph, aWriter);
		}else if(aGraph instanceof DefaultDirectedWeightedGraph) {
			aWriter.write("#gerichtet");
			aWriter.write(System.getProperty("line.separator"));
			aWriter.write("#gewichtet#attributiert");
			tmp = saveGewichtetGerichtetGraph(aGraph, aWriter);
		}				
		return tmp;
	}
	
	private boolean saveGraphStringDefaultWeightedEdge(AbstractGraph<String, DefaultWeightedEdge> agraph, FileWriter aWriter) throws IOException{
		boolean tmp = false;
		if(agraph instanceof WeightedPseudograph){
			aWriter.write("#ungerichtet");
			aWriter.write(System.getProperty("line.separator"));
			aWriter.write("#gewichtet");
			tmp = saveGewichtetUnGerichtetGraph(agraph, aWriter);
		}else if(agraph instanceof DefaultDirectedWeightedGraph){
			aWriter.write("#gerichtet");
			aWriter.write(System.getProperty("line.separator"));
			aWriter.write("#gewichtet");
			tmp = saveGewichtetGerichtetGraph(agraph, aWriter);
		}		
		return tmp;
	}
		
	private boolean saveGewichtetGerichtetGraph(AbstractGraph<?, DefaultWeightedEdge> agraph, FileWriter aWriter) throws IOException {
		aWriter.write(System.getProperty("line.separator"));
		DefaultDirectedWeightedGraph<?, DefaultWeightedEdge> tgraph = (DefaultDirectedWeightedGraph<?, DefaultWeightedEdge>)agraph;
		Iterator<DefaultWeightedEdge> iterWeightEdge = tgraph.edgeSet().iterator();
		while(iterWeightEdge.hasNext()){
			DefaultWeightedEdge dwe= iterWeightEdge.next();
			Object frist =  tgraph.getEdgeSource(dwe);  
			Object second = tgraph.getEdgeTarget(dwe);			
			double gewichtung = tgraph.getEdgeWeight(dwe);
			if(isString){
				aWriter.write(frist.toString()+ "," +second.toString()+ "," + gewichtung);
			}else{
				AbstractGraph<Knoten, DefaultWeightedEdge> aKDWGraph = (AbstractGraph<Knoten, DefaultWeightedEdge>)agraph;
				Knoten a = (Knoten) frist;
				Knoten b = (Knoten) second;
				int fristAttr = getKnotenAttr(aKDWGraph, a.getName());
				int secAttr = getKnotenAttr(aKDWGraph, b.getName());
				aWriter.write(a.getName()+","+fristAttr+","+b.getName()+","+secAttr+"," + gewichtung);
			}
			aWriter.write(System.getProperty("line.separator"));
		}
		aWriter.write(System.getProperty("line.separator"));
		aWriter.flush();
		// Schließt den Stream
		aWriter.close();
		out("Speicherung Erfolgreich!");		
		return true;
	}

	private boolean saveGewichtetUnGerichtetGraph(AbstractGraph<?, DefaultWeightedEdge> aGraph, FileWriter aWriter)throws IOException{
		aWriter.write(System.getProperty("line.separator"));
		WeightedPseudograph<?, DefaultWeightedEdge> tgraph = (WeightedPseudograph<?, DefaultWeightedEdge>)aGraph;
		Iterator<DefaultWeightedEdge> iterWeightEdge = tgraph.edgeSet().iterator();
		while(iterWeightEdge.hasNext()){
			DefaultWeightedEdge dwe= iterWeightEdge.next();
			Object frist =  tgraph.getEdgeSource(dwe);  
			Object second = tgraph.getEdgeTarget(dwe);			
			double gewichtung = tgraph.getEdgeWeight(dwe);
			if(isString){
				aWriter.write(frist.toString()+ "," +second.toString()+ "," + gewichtung);
			}else{
				AbstractGraph<Knoten, DefaultWeightedEdge> aKDWGraph = (AbstractGraph<Knoten, DefaultWeightedEdge>)aGraph;
				
				Knoten a = (Knoten) frist;
				Knoten b = (Knoten) second;
				int fristAttr = getKnotenAttr(aKDWGraph, a.getName());
				int secAttr = getKnotenAttr(aKDWGraph, b.getName());
				aWriter.write(a.getName()+","+fristAttr+","+b.getName()+","+secAttr+"," + gewichtung);
			}
			aWriter.write(System.getProperty("line.separator"));
		}
		aWriter.write(System.getProperty("line.separator"));
		aWriter.flush();
		// Schlie�t den Stream
		aWriter.close();
		out("Speicherung Erfolgreich!");		
		return true;
	}
		
	private int getKnotenAttr(AbstractGraph<Knoten, DefaultWeightedEdge> aGraph, String knotenName){
		Iterator<Knoten> iterVertex =  aGraph.vertexSet().iterator();
		while(iterVertex.hasNext()){
			Knoten a = iterVertex.next();
			if(a.getName().equals(knotenName)) return a.getKnotenarttibutt();
		}
		return 0;
	}
		
	private boolean saveGraphStringDefaultEdge(AbstractGraph<String, DefaultEdge> aGraph, FileWriter aWriter) throws IOException {
		if (aGraph instanceof UndirectedGraph)
			aWriter.write("#ungerichtet");
		else if (aGraph instanceof DirectedGraph)
			aWriter.write("#gerichtet");
		aWriter.write(System.getProperty("line.separator"));
		Iterator<?> iterGraph = aGraph.edgeSet().iterator();
		while (iterGraph.hasNext()) {
			DefaultEdge entry = (DefaultEdge) iterGraph.next();			
			String frist = aGraph.getEdgeSource(entry);
			String second = aGraph.getEdgeTarget(entry);

			aWriter.write(frist + "," + second);
			aWriter.write(System.getProperty("line.separator"));
		}
		// Platformunabhängiger Zeilenumbruch wird in den Stream geschrieben
		aWriter.write(System.getProperty("line.separator"));
		// Schreibt den Stream in die Datei
		// Sollte immer am Ende ausgeführt werden, sodass der Stream
		// leer ist und alles in der Datei steht.
		aWriter.flush();
		// Schließt den Stream
		aWriter.close();
		out("Speicherung Erfolgreich!");
		return true;   	
	}
}
